/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Modelo;

/**
 *
 * @author vanesa
 */
public class SolucionTablero6x6 {
    
    /**VerificarColumna: Este método se encarga de verificar que el valor a ingresar
     * en el tablero no este en la columna.
     * @param tablero "Tablero de la partida en estado actual del juego."
     * @param valor "Valor a chequear que no se repita en la columna."
     * @param fila "Entero que representa la fila en donde se va a colocar ese 
     * valor a verificar en la columan."
     * @return boolean "Retorna true si ese valor pasado como parámetro
     * ya se encuentra en la columna, de lo contrario retorna false."
     */
	public boolean VerificarColumna(int [][] tablero, int valor, int fila){
		boolean esta= false;
		int i=0;
		while((i<tablero.length)&&(!esta)){
			if (valor == tablero [fila][i])
				esta=true;
			i++;
		}
		return esta;
	}
	
	/**VerificarFila: Este método se encarga de verificar que el valor a ingresar
     * en el tablero no este en la fila.
     * @param tablero "Tablero de la partida en estado actual del juego."
     * @param valor "Valor a chequear que no se repita en la fila."
     * @param columna "Entero que representa la columna en donde se va a colocar ese 
     * valor a verificar en la fila."
     * @return boolean "Retorna true si ese valor pasado como parámetro
     * ya se encuentra en la fila, de lo contrario retorna false."
     */
	public boolean VerificarFila(int [][] tablero, int valor, int columna){
		boolean esta= false;
		int i=0;
		while((i<tablero.length)&&(!esta)){
			if (valor == tablero [i][columna])
				esta=true;
			i++;
		}
		return esta;
	}
	
     /**VerificarCuadricula: Este método se encarga de verificar que el valor a ingresar
     * en el tablero no este en la cuadricula en la que va a ser ingresado.
     * @param tablero "Tablero de la partida en estado actual del juego."
     * @param valor "Valor a chequear que no se repita en la fila."
     * @param columna "Entero que representa la columna en donde se va a colocar ese 
     * valor a verificar en la cuadricula."
     * @param fila "Entero que representa la fila en donde se va a colocar ese 
     * valor a verificar en la cuadricula."
     * @return boolean "Retorna true si ese valor pasado como parámetro
     * ya se encuentra en la cuadricula, de lo contrario retorna false."
     */
	 public boolean VerificarCuadricula(int [][] tablero, int fila, int columna, int valor){
            boolean esta=false;
            int i= (fila / 2)*2;
            int j= (columna / 3)*3;
            int m=i+2;
            int n=j+3;
            for(int k=i;k<m;k++)
                for(int l=j;l<n;l++){
                    if(tablero[k][l]==valor)
                        esta=true;}
            
            return esta;
        }
	
  /* Matríz con los numeros usados en el subcuadrado i-esimo.
  * Los subcuadrados se numeran asi:
  *    0 1 2
  *    3 4 5
  *    6 7 8
  * usadosCuadrado[i][j] es true si esta usado el numero j+1 en el subcuadrado i-esimo.*/
  private static boolean usadosCuadrado[][];

  /* Matríz con los numeros usados en la fila i-esima.
  * Las lineas se numeran de 0 a 8 de arriba a bajo.
  * usadosLinea[i][j] es true si el numero j+1 ya esta usado en la linea i-esima.*/
  private static boolean usadosFila[][];

  /* Matríz con los numeros usados en la columna i-esima.
  * Las columnas se numeran de 0 a 8 de izquierda a derecha.
  * usadosColumna[i][j] es true si el numero j+1 ya esta usado en la columna i-esima.*/
  private static boolean usadosColumna[][];
  
  
  public SolucionTablero6x6(){}

   /** marca: a usado el valor numero, situado en (fila,columna), en la tabla de posibles.
    */
  void marca(int numero, int fila, int columna, boolean usado,int [][] tablero) {
       // System.out.println(fila/2*2+columna/3);
	usadosCuadrado[fila/2*2+columna/3][numero-1] = usado;
	usadosFila[fila][numero-1] = usado;
	usadosColumna[columna][numero-1] = usado;
	if (usado){
		tablero[fila][columna]=numero;
	}
	else{
		tablero[fila][columna]=0;
	}
  }

  /** Constructor: Inicializa el tablero.
   * @param tablero "Toma el tablero inicial del juego."
  */
  public SolucionTablero6x6(int [][] tablero) {
	usadosCuadrado = new boolean[6][6];
	usadosFila = new boolean[6][6];
	usadosColumna  = new boolean[6][6];
	for (int f=0 ; f<6 ; f++) {
		for (int c=0 ; c<6 ; c++){
			if (tablero[f][c] != 0){
				marca(tablero[f][c],f,c,true,tablero);
			}
		}
	}
  }

   /**posibles: Devuelve un array de 9 booleanos con los valores posibles 
   * de la posicion dada.
   * @param fila   "Este entero corresponde a la fila del casillero
   * a la que se le va a calcular los posibles valores que puede asumir."
   * @param columna "Este entero corresponde a la columna del casillero
   * a la que se le va a calcular los posibles valores que puede asumir."
   */
  public boolean[] posibles(int fila, int columna) {
	boolean[] res = new boolean[6];
	for (int i=0 ; i<6 ; i++) {
	  res[i] = !usadosCuadrado[fila/2*2+columna/3][i] && !usadosFila[fila][i] && !usadosColumna[columna][i];
	}
	return res;
  }


 


  /** intenta: Busca la solucion.
  * @param pos "Es la posicion que indica el avance del backtracking".
  * @param tablero "En un principio toma el tablero inicial de la partida,
  * pero luego de varias llamadas recursivas se va modificando."
  * @return boolean " Devuelve true si encuentra una posible solución 
  * de lo contrario retorna false."
  */
  public boolean intenta(int pos, int [][] tablero) {
	if (pos == (tablero.length*tablero[0].length)) return true;
 	int fila = pos / (tablero.length);
	int columna = pos % (tablero.length);
	if (tablero[fila][columna] != 0) {
	  return intenta(pos+1,tablero);
	} else {
	  boolean[] candidatos = posibles(fila,columna);

	  for (int i=0 ; i<6 ; i++) {
		if (candidatos[i]) {
		  marca(i+1,fila,columna,true,tablero);
		  if (intenta(pos+1,tablero))
			return true;
		  marca(i+1,fila,columna,false,tablero);
		}
	  }
	  return false;
	}
  }


    /** resuleve: Busca la solucion.
  * @param pos "Es la posicion que indica el avance del backtracking".
  * @param tablero "En un principio toma el tablero inicial de la partida,
  * pero luego de varias llamadas recursivas se va modificando."
  * @return int[][] " Devuelve el tablero con la solución en caso de que el
  * tablero pasado como parámetro tenga solución, sino devuelve el tablero
  * inicial"
  */
   public int [][] Resolver(int pos, int [][] tab) {
       int [][] tablero=tab;
	if (pos == (tablero.length*tablero[0].length)) return tablero;
 	int fila = pos / (tablero.length);
	int columna = pos % (tablero.length);
	if (tablero[fila][columna] != 0) {
	  return Resolver(pos+1,tablero);
	} else {
	  boolean[] candidatos = posibles(fila,columna);

	  for (int i=0 ; i<6 ; i++) {
		if (candidatos[i]) {
		  marca(i+1,fila,columna,true,tablero);
		  if (intenta(pos+1,tablero))
			return tablero;
		  marca(i+1,fila,columna,false,tablero);
		}
	  }
      this.mostrar(tablero);
	  return tablero;
	}
    }

    



         


  /* imprime por pantalla el tablero (en la perminal) */
 public void mostrar(int [][] tablero) {
        for (int l=0 ; l<tablero.length ; l++) {
	  for (int c=0 ; c<tablero[l].length ; c++)
		System.out.print(tablero[l][c]+" ");
	  System.out.println();
	}
    }
}

